/* ----------------------------------------------------------------------------

	pax.util.js Copyright (C) 2004, 2008 Mikkel Bergmann, Pointful

	Licence
	-------
	
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

	See lgpl.txt for licence details

---------------------------------------------------------------------------- */


/*
	Script: pax.util
		This is the utility part of the PAX library, it has handy methods to do various tasks
		
	Author:
		Mikkel Bergmann, <http://www.pointful.com>

*/
/*	
	WIP: This is being integrated with the PAX base library.
*/

var pax = pax || {};
pax.util = pax.util || {};

/*	Property: pax.util.genElementID
		Global Gnerated element unique id	*/
pax.util.genElementID = 0;

//	Sets attribute(s) for a given element
//	This won't work in certain instances for IE6 down as some attributes cannot be set in IE.
//	The only known hack is to set the attributes as the element is being generated, though see
//	the collection manager for a possible better hack.
pax.util.attrib = function( element, attribs ) {
	for( var attrib in attribs ) {
		var value = attribs[attrib];
		element[attrib] = value;
		if (element.setAttribute)element.setAttribute(attrib, value);
	}
	
	return element;
};

//	Creates an element, note: name defaults to id
pax.util.genElement = function( type, args ) {
	args = args || {};
	args.id = (typeof(args.id) != 'undefined') ? args.id : pax.getNextId();
	args.name = (typeof(args.name) != 'undefined') ? args.name : args.id;
	
	if (pax.isIe6Down) {
		//	Create using a string for Ie6 and down
		//	TODO: check if it is an element with start and end tag, or just a singular tag
		var eleStr = '<' + type + ' ';
		for( var i in args ) {
			eleStr += i + '="' + args[i].split('"').join('\\"') + '" ';
		}
		eleStr += '/>';
		
		var ele = document.createElement( eleStr );
	}
	else {
		var ele = document.createElement(type);
		pax.util.attrib(ele, args);
	}
	
	return ele;
};

//	Removes an element
pax.util.removeElement = function( ele ) {
	if( ele.tagName != 'BODY' ) {
		if( pax.isIe ) {
			var destroy = document.createElement('div');
			destroy.appendChild( ele );
			destroy.innerHTML = '';
		} else {
			if( ele && ele.parentNode ) {
				ele.parentNode.removeChild( ele );
			}
		}
	}
};


/*	Method: pax.util.getAgent
	Private method, detects browser string, you should detect browser capability instead, handy in some instances. This is run on startup by default
	
	Parameters:
		none

	Example:
		(start code)
			<div>Is IE: [:= pax.isIe :]</div>
			<div>Is Safari: [:= pax.isSafari :]</div>
			<div>Is Gecko: [:= pax.isGecko :]</div>
		(end)
		Will show the detected status of each browser type, we don't call the detection method, as it is automatically run when this library is loaded.

	This is automatically run when this library is loaded.
*/
pax.util.getAgent = function() {
	pax.isIe = false;
	pax.isIe6Down = false;
	pax.isOpera = false;
	pax.isSafari = false;
	pax.isGecko = false;
	pax.isIPhone = false;
	
	if( navigator.userAgent.indexOf("Safari") > 0 ) {
		pax.isSafari = true;
		pax.isIPhone = ( ( navigator.userAgent.indexOf('iPhone') != -1 ) || ( navigator.userAgent.indexOf('iPod') != -1 ) );
	} else if( navigator.product == "Gecko" ) {
		pax.isGecko = true;
	} else if( window.opera ){
		pax.isOpera = true;
	} else {
		pax.isIe = true;
		var version = (navigator.userAgent.toLowerCase().match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1];
		pax.isIe6Down = (version == '6.0');
	}
};

//	Run the detection on include of this file.
pax.util.getAgent();

if( pax.isIe ) {
	//	Hack to eliminate background image flicker in IE. http://mister-pixel.com/#Content__state=is_that_simple
    document.execCommand( "BackgroundImageCache", false, true );
};


/*	Method: pax.util.copyObj
	Returns a new object with the attribues of the given object, optionally removing duplicates
	
	Parameters:
		obj - The object to copy
		allowDupes - Optionally remove duplicate items

	Example:
		(start code)
			<div id='pax.util.copyObj.example1'></div>
			[:.
				var basket1 = [ 'apple', 'banana', 'pear' ];
				var basket2 = pax.util.copyObj( basket1 );
				basket2[basket2.length] = 'lime';
				pax.$('pax.util.copyObj.example1').innerHTML = 'basket1: ' + pax.util.toString( basket1 ) + '<hr>basket2: ' + pax.util.toString( basket2 );
			:]
		(end)
		This will copy basket1 into basket2, and then add a lime to basket2
		
	Example:
		(start code)
			<div id='pax.util.copyObj.example2'></div>
			[:.
				var basket1 = [ 'apple', 'banana', 'pear', { chocolate: 'dark Belgian', strawberries: 'Queensland' } ];
				var basket2 = pax.util.copyObj( basket1 );
				var wineCooler = { ice: 'cold', bottles: ['Yalumba chardonnay', 'Penfolds five'], corkscrew: { automatic: 'powercorker2000', manual: 'waiters friend' } };
				basket2[basket2.length] = wineCooler;
				pax.$('pax.util.copyObj.example2').innerHTML = 'basket1: ' + pax.util.toString( basket1 ) + '<hr>basket2: ' + pax.util.toString( basket2 );
			:]
		(end)
		This will copy basket1 into basket2, and then add a complex wineCooler object to basket2
		
	Example:
		(start code)
			<div id='pax.util.copyObj.example3'></div>
			[:.
				var basket1 = [ 'apple', 'banana', 'pear', { chocolate: 'dark Belgian', strawberries: 'Queensland' } ];
				var basket2 = pax.util.copyObj( basket1 );
				var wineCooler = { basketOne: basket1, ice: 'cold', bottles: ['Yalumba chardonnay', 'Penfolds five'], corkscrew: { automatic: 'powercorker2000', manual: 'waiters friend' } };
				basket2[basket2.length] = wineCooler;
				pax.$('pax.util.copyObj.example3').innerHTML = 'basket1: ' + pax.util.toString( basket1 ) + '<hr>basket2: ' + pax.util.toString( basket2 );
			:]
		(end)
		This will copy basket1 into basket2, and then add a complex wineCooler object to basket2, which already contains basket1, thus creating a circular reference
*/
pax.util.copyObj = function( obj, allowDupes ) {
	allowDupes = ( typeof( allowDupes ) != 'undefined' )?allowDupes : true;
	var newObj = ( pax.util.getType( obj ) == 'array' )?[] : {};

	if( pax.util.getType( obj ) == 'array' ) {
		for( var a in obj ) {
			if( allowDupes )newObj[newObj.length] = obj[a];
			else {
				if( ! pax.util.arrayHasValue( obj[a], newObj ) ) {
					newObj[newObj.length] = obj[a];
				}
			}
		}
	}
	else {
		for( var a in obj )newObj[a] = obj[a];
	}

	return newObj;
};


/*	Method: pax.util.joinObj
	Returns an object with the attribues of both obj1 and obj2. Assumes return object type is to be the same as obj1
	
	Parameters:
		obj1 - The first object to join
		obj2 - The second object to join

	Example:
		(start code)
			<div id='pax.util.joinObj.example1'></div>
			[:.
				var basket1 = [ 'apple', 'banana', 'pear' ];
				var basket2 = [ 'orange', 'lemon', 'lime' ];
				var fruitBasket = pax.util.joinObj( basket1, basket2 );
				pax.$('pax.util.joinObj.example1').innerHTML = pax.util.toString( fruitBasket );
			:]
		(end)
		This will assign [ 'apple', 'banana', 'pear', 'orange', 'lemon', 'lime' ] to fruitBasket;
		
	Example:
		TODO: This example crashes in IE
		(start code)
			<div id='pax.util.joinObj.example2'></div>
			[:.
				var checkBoxMap = {
					'pax.cache.template.js': [ 'pax.js', 'pax.cache.js', 'pax.template.js' ],
					'pax.template.js': [ 'pax.js', 'pax.cache.js', 'pax.cache.template.js', 'pax.template.modifier.js' ],
					'pax.template.modifier.js': [ 'pax.template.js' ],
					'pax.widget.js': [ 'pax.js' ],
					'pax.validate.js': [ 'pax.js', 'pax.util.js' ],
					'pax.fx.js': [ 'pax.js', 'pax.util.js' ]
				};
				
				for( var c in checkBoxMap ) {
					var newDeps = [];
					for( var dep in checkBoxMap[c] ) {
						if( pax.util.hasKey( checkBoxMap[c][dep], checkBoxMap ) ) {
							newDeps = pax.util.joinObj( checkBoxMap[c], checkBoxMap[checkBoxMap[c][dep]], false );
						} else {
							newDeps[newDeps.length] = checkBoxMap[c][dep];
						}
					}
					if( newDeps != [] )checkBoxMap[c] = newDeps;
				}
				
				pax.$('pax.util.joinObj.example2').innerHTML = pax.util.toString( checkBoxMap ).split(',').join(',<b'+'r>');
				
			:]
		(end)
*/
/*
	TODO: This and pax.defaultArgs do almost the same thing, so combine them.
*/
pax.util.joinObj = function( obj1, obj2, allowDupes ) {
	allowDupes = ( typeof( allowDupes ) != 'undefined' )? allowDupes : true;
	var newObj = pax.util.copyObj( obj1, allowDupes );

	if( pax.util.getType( obj1 ) == 'array' ) {
	//	if( typeof( obj1 ) == typeof( [] ) ) {
		for( var a in obj2 ) {
			if( allowDupes )newObj[newObj.length] = obj2[a];
			else {
				if( ! pax.util.arrayHasValue( obj2[a], newObj ) ) {
					newObj[newObj.length] = obj2[a];
				}
			}
		}
	}
	else {
		for( var a in obj2 )newObj[a] = obj2[a];
	}
	return newObj;
};


/*	Method: pax.util.getType
	Returns the type of object that matches the element passed in.

	Parameters:
		obj - the object to inspect.

	Returns:
		'element' - if obj is a DOM element node
		'textnode' - if obj is a DOM text node
		'whitespace' - if obj is a DOM whitespace node
		'array' - if obj is an array
		'object' - if obj is an object
		'string' - if obj is a string
		'number' - if obj is a number
		'boolean' - if obj is a boolean
		'function' - if obj is a function
		false - (boolean) if the object is not defined or none of the above.
		
	Example:
		(start code)
			<div id='pax.util.getType.example1'></div>
			[:.
				var o = pax.$('pax.util.getType.example1');
				o.innerHTML += "DOM element node: " + pax.util.getType( pax.$('pax.util.getType.example1') ) + '<'+'br>';
				o.innerHTML += "Array: " + pax.util.getType( [] ) + '<'+'br>';
				o.innerHTML += "Object: " + pax.util.getType( {} ) + '<'+'br>';
				o.innerHTML += "String: " + pax.util.getType( '' ) + '<'+'br>';
				o.innerHTML += "Number: " + pax.util.getType( 1 ) + '<'+'br>';
				o.innerHTML += "Boolean: " + pax.util.getType( true ) + '<'+'br>';
				o.innerHTML += "Function: " + pax.util.getType( function(){} ) + '<'+'br>';
				o.innerHTML += "Not defined(false): " + pax.util.getType(  ) + '<'+'br>';
			:]
				'textnode' - if obj is a DOM text node
				'whitespace' - if obj is a DOM whitespace node
		(end)
		This will Show the different type strings that getType can return.
		
*/
pax.util.getType = function( obj ) {
	var type = typeof( obj );
	if( type == 'undefined' || obj === null )return false;
	if( type == 'object' ) {
		if( obj.push )return 'array';
		if( obj.htmlElement )return 'element';
		if( obj.nodeName ) {
			switch (obj.nodeType){
				case 1: return 'element';
				case 3: return (obj.nodeValue && obj.nodeValue.test && obj.nodeValue.test(/\S/)) ? 'textnode' : 'whitespace';
			}
		}
	}
	return type;
};


/*	Method: pax.util.toString
	Returns a string representation of the object passed in.

	Warning:
	Do NOT pass in objects that are self referencing

	Parameters:
		obj - the object to inspect.
		
	Example:
		(start code)
			<div id="pax.util.toString.example1"></div>
			[:.
				var config =  {
					url: '/pax/myEditController.php',
					offset: 4, 
					columns: [
						'notes',
						{
							offset: 3,
							foo: function( text ) { alert( text ) }
						}
					],
					test: function(a,b){return a > b;}
				};
				config.self = config;
				config.columns[1]['me'] = config;
				pax.$( 'pax.util.toString.example1' ).innerHTML = pax.util.toString( config );
			:]
		(end)
		This will show an example with two circular references.
		
	Example:
		(start code)
			<div id="pax.util.toString.example2"></div>
			[:.
				pax.$( 'pax.util.toString.example2' ).innerHTML = pax.util.toString( pax.util.toString );
			:]
		(end)
		This will show the <pax.util.toString> function ;o)
		
	Note that this was inspired by mootools
*/
pax.util.toString = function( obj, prev ) {
	prev = prev || [];
	//	This will show '*circular ref*', when we have string values repeated.
	if( pax.util.hasValue( obj, prev ) && pax.util.getType( obj ) == 'object' ) {
		return '"*circular ref*: ' + obj + '"';
	} else {
		var result = [];
		prev.push( obj );
		var type = pax.util.getType(obj);
		switch( type ) {
			case 'string':
				return '"' + obj.replace( new RegExp('(["\\\\])', 'g'), '\\$1') + '"';
			case 'array':
				for( var i = 0; i < obj.length; i++ )result.push( pax.util.toString( obj[i], prev ) );
				return '[' + result.join(',') + ']';
			case 'object':
				for (var property in obj)result.push( '"' + property + '":' + pax.util.toString( obj[property], prev ) );
				return '{' + result.join(',') + '}';
		}
	}
	return String( obj );
};


/*	Method: pax.util.pprint
	Returns a pretty printed string representation of the object passed in.

	Warning:
	Do NOT pass in objects that are self referencing

	Parameters:
		obj - the object to inspect.
		
	Example:
		(start code)
			<div id="pax.util.pprint.example1"></div>
			[:.
				var config =  {
					url: '/pax/myEditController.php',
					offset: 4, 
					columns: [
						'notes',
						{
							offset: 3,
							foo: function( text ) { alert( text ) }
						}
					],
					test: function(a,b){return a > b;}
				};
				config.self = config;
				config.columns[1]['me'] = config;
				pax.$( 'pax.util.pprint.example1' ).innerHTML = '<pre>' + pax.util.pprint( config ) + '</pre>';
			:]
		(end)
		This will show an example with two circular references.
		
	Example:
		(start code)
			<div id="pax.util.pprint.example2"></div>
			[:.
				pax.$( 'pax.util.pprint.example2' ).innerHTML = '<pre>' + pax.util.pprint( pax.util.pprint ) + '</pre>';
			:]
		(end)
		This will show the <pax.util.pprint> function ;o)
		
	TODO: This is very similar to the toString function, except for the indent; we should combine these...
*/
pax.util.pprint = function( obj, prev, indent ) {
	if( typeof(indent) == 'undefined' )indent = 0;
	prev = prev || [];
	if( pax.util.hasValue( obj, prev ) && pax.util.getType( obj ) == 'object' ) {
		return '"*circular ref*: ' + obj + '"';
	} else {
		var result = [];
		prev.push( obj );
		var type = pax.util.getType(obj);
		
		var indentText = '';
		for( var x = 0; x < indent; x++ )indentText += '\t';
		
		switch( type ) {
			case 'string':
				return ' "' + obj.replace( new RegExp('(["\\\\])', 'g'), '\\$1') + '"';
			case 'array':
				for( var i = 0; i < obj.length; i++ )result.push( indentText + pax.util.pprint( obj[i], prev, indent + 1 ) );
				return indentText + '[\n' + result.join(',') + indentText + '\n]';
			case 'object':
				for (var property in obj)result.push( indentText + '"' + property + '":' + pax.util.pprint( obj[property], prev, indent + 1 ) );
				return '{\n' + result.join(',\n') + '\n' + indentText + '}';
		}
	}
	return String( obj );
};


/*	Method: pax.util.hasKey
	Returns the key, if it finds a key from a dict or array
	
	Parameters:
		key - The key to look for
		obj - The dictionary or array to look in

	Example:
		(start code)
			<div id="pax.util.hasKey.example1"></div>
			[:.
				var fruitBasket = { orange: 3, lemon: 2, lime: 0 };
				pax.$('pax.util.hasKey.example1').innerHTML = "Is there a key of 'line' in the fruit basket?: " + pax.util.hasKey( 'lime', fruitBasket );
			:]
		(end)
		This will show true

	Example:
		(start code)
			<div id="pax.util.hasKey.example2"></div>
			[:.
				var fruitBasket = { orange: 3, lemon: 2, lime: 0 };
				pax.$('pax.util.hasKey.example2').innerHTML = "Is there a 'kiwi' in the fruit basket?: " + pax.util.hasKey( 'kiwi', fruitBasket );
			:]
		(end)
		This will show false
*/
pax.util.hasKey = function( key, obj ) {
	//	Note that the VAR keyword in front of item is necessary if using this in a template, or we get an error: 'Object doesn't support this action'.
	for( var i in obj ) {
		if( key == i )return i;
	}
	return false;
};

/*	Counts number of items in an object
*/
pax.util.numItems = function( obj ) {
	var count = 0;
	for( var i in obj ) {
		count += 1;
	}
	return count;
};


/*	Method: pax.util.hasValue
	Returns the value, if it finds a value in an object or dictionary
	
	Parameters:
		key - The key to look for
		dict - The object or dictionary to look in

	Example:
		(start code)
			<div id="pax.util.hasValue.example1"></div>
			[:.
				var fruitBasket = { orange: 3, lemon: 2, lime: 0 };
				pax.$('pax.util.hasValue.example1').innerHTML = "Does the fruit basket have a value of 2?: " + pax.util.hasValue( 2, fruitBasket );
			:]
		(end)
		This will show true
		
	Example:
		(start code)
			<div id="pax.util.hasValue.example2"></div>
			[:.
				var fruitBasket = { orange: 3, lemon: 2, lime: 0 };
				pax.$('pax.util.hasValue.example2').innerHTML = "Does the fruit basket have a value of 7?: " + pax.util.hasValue( 7, fruitBasket );
			:]
		(end)
		This will show false
*/
pax.util.hasValue = function( value, dict ) {
	//	Note that the VAR keyword in front of item is necessary if using this in a template, or we get an error: 'Object doesn't support this action'.
	for( var i in dict ) {
		if( value == dict[i] )return i;
	}
	return false;
};


/*	Method: pax.util.arrayHasValue
	Returns the index, if it finds a value in an array
	
	Parameters:
		key - The key to look for
		arr - The array to look in

	Example:
		(start code)
			<div id="pax.util.arrayHasValue.example1"></div>
			[:.
				var fruitBasket = [ 'orange', 'lemon', 'lime' ];
				pax.$('pax.util.arrayHasValue.example1').innerHTML = "Is there a 'lemon' in the fruit basket?: " + pax.util.arrayHasValue( 'lemon', fruitBasket );
			:]
		(end)
		This will show true
		
	Example:
		(start code)
			<div id="pax.util.arrayHasValue.example2"></div>
			[:.
				var fruitBasket = [ 'orange', 'lemon', 'lime' ];
				pax.$('pax.util.arrayHasValue.example2').innerHTML = "Is there a 'passionfruit' in the fruit basket?: " + pax.util.arrayHasValue( 'passionfruit', fruitBasket );
			:]
		(end)
		This will show false
		
*/
pax.util.arrayHasValue = function( value, arr ) {
	//	Note that the VAR keyword in front of item is necessary if using this in a template, or we get an error: 'Object doesn't support this action'.
	for( var i = 0; i < arr.length; i++ ) {
		if( value == arr[i] )return i;
	}
	return false;
};


/*	Method: pax.util.getTarget
	Returns the target of an event
*/
pax.util.getTarget = function( e ) {
	if( pax.isIe )return e.target || window.event.srcElement;
	else return e.target;
};

/*	Method: pax.util.getPosition
	Locates position and dimensions of an object
	
	Parameters:
		element - The DOM element to find the position / dimensions of
		excludeParent - Don't take the parent offset into account, to be used if adding an element absolutely positioned inside the same parent element

	Returns:
		A dictionary with x, y, width, height of element. Does not work for the window.

	Example:
		(start code)
			Excluding parent node offsets (as we're positioning a box inside the same parent) - red box should appear at SW corner
			<div id="pax.util.getPosition.example1.divA" style="border: solid 1px #c0c0c0; position: absolute; top: 50px; left: 40px;">Pos - </div>
			<div id="pax.util.getPosition.example1.divB" style='background:red;position:absolute;width:10px; height:10px;'></div>
			[:.
				var myDiv = pax.$('pax.util.getPosition.example1.divA');
				var pos = pax.util.getPosition( myDiv, false );
				myDiv.innerHTML += 'x: ' + pos.x + ' y: ' + pos.y + ' width: ' + pos.width + ' height: ' + pos.height;
				var pos = pax.util.getPosition( myDiv, false );
				var myArrow = pax.$('pax.util.getPosition.example1.divB');
				pax.util.setPosition( myArrow, { x: pos.x + pos.width, y: pos.y + pos.height } );
			:]
		(end)
		pos will be an object that contains {x: int, y: int, width: int, height: int}

	Example:
		(start code)
			Including parent nodes (notice the large y value)
			<div style="border: solid 1px #c0c0c0" id="pax.util.getPosition.example2">Pos - </div>
			[:.
				var myDiv = pax.$('pax.util.getPosition.example2');
				var pos = pax.util.getPosition( myDiv );
				myDiv.innerHTML += 'x: ' + pos.x + ' y: ' + pos.y + ' width: ' + pos.width + ' height: ' + pos.height;
			:]
		(end)
		pos will be an object that contains {x: int, y: int, width: int, height: int}

	Example:
		(start code)
			<span style="border: solid 1px #c0c0c0" id="pax.util.getPosition.example3">Pos - </span>
			[:.
				var mySpan = pax.$('pax.util.getPosition.example3');
				var pos = pax.util.getPosition( mySpan );
				mySpan.innerHTML += 'x: ' + pos.x + ' y: ' + pos.y + ' width: ' + pos.width + ' height: ' + pos.height;
			:]
		(end)
		pos will be an object that contains {x: int, y: int, width: int, height: int}

	Example:
		(start code)
			<span style="border: solid 1px #c0c0c0; position: absolute; top: 50px; left: 40px;" id="pax.util.getPosition.example4">Pos - </span>
			[:.
				var mySpan = pax.$('pax.util.getPosition.example4');
				var pos = pax.util.getPosition( mySpan );
				mySpan.innerHTML += 'x: ' + pos.x + ' y: ' + pos.y + ' width: ' + pos.width + ' height: ' + pos.height;
			:]
		(end)
		pos will be an object that contains {x: int, y: int, width: int, height: int}

	Example:
		(start code)
			<span style="border: solid 1px #c0c0c0; position: absolute; top: 50px; left: 40px;" id="pax.util.getPosition.example5">Pos - </span>
			[:.
				var newSpan = document.createElement( 'SPAN' );
				newSpan.innerHTML = 'Span';
				newSpan.id = 'pax.util.getPosition.example5.span';
				newSpan.style.position = 'absolute';
				newSpan.style.left = '100px';
				newSpan.style.top = '200px';
				document.body.appendChild( newSpan );
				
				var mySpan = pax.$('pax.util.getPosition.example5');
				var myNewSpan = pax.$('pax.util.getPosition.example5.span');
				var pos = pax.util.getPosition( myNewSpan );
				mySpan.innerHTML += 'x: ' + pos.x + ' y: ' + pos.y + ' width: ' + pos.width + ' height: ' + pos.height;
				
				document.body.removeChild( newSpan );
			:]
		(end)
		pos will be an object that contains {x: int, y: int, width: int, height: int}, of the dynamically created newSpan element
*/
pax.util.getPosition = function( element, excludeParent ) {
	excludeParent = ( typeof( excludeParent ) != 'undefined' && excludeParent == false );
	var offsetLeft = 0;
	var offsetTop = 0;

	// Divs can be affected by scroll offsets - this is needed in datagrid.
	// var is_div = /^div$/i.test( element.tagName );
	if( /^div$/i.test( element.tagName ) ) {
		if( element.scrollLeft )offsetLeft = element.scrollLeft;
		if( element.scrollTop )offsetTop = element.scrollTop;

		// We should add the scroll offset too in some instances...?
		// Maybe only if something is absolutely positioned?
		// offsetLeft += ( document.body.scrollLeft )? document.body.scrollLeft: ( window.pageXOffset )? window.pageXOffset : 0;
		// offsetTop += ( document.body.scrollTop )? document.body.scrollTop: ( window.pageYOffset )? window.pageYOffset: 0;
	}

	var pos = {
		x: element.offsetLeft - offsetLeft, 
		y: element.offsetTop - offsetTop, 
		width: element.offsetWidth,
		height: element.offsetHeight
	};
	
	if( ! excludeParent ) {
		if( element.offsetParent ) {
			var tmp = pax.util.getPosition( element.offsetParent );
			pos.x += tmp.x;
			pos.y += tmp.y;
		}
	}
	
	return pos;
};



/*	Method: pax.util.setPosition
	Sets position and dimensions of an object
	
	Parameters:
		element - The DOM element to set the position / dimensions of
		pos - Object as returned from <pax.util.getPosition>

	Example:
		(start code)
			<div id='pax.util.getPosition.example1.divA' style="border: solid 1px #c0c0c0; background: blue; position: absolute; top: 80px; left: 40px;">Click me to cover me with the red div!</div>
			<div id='pax.util.getPosition.example1.divB' style='background:red;position:absolute; left: 10px; top: 40px;'>I'm the red div!</div>
			[:.
				pax.event.bind( pax.$('pax.util.getPosition.example1.divA'), 'click', function() {
					var pos = pax.util.getPosition( pax.$('pax.util.getPosition.example1.divA'), false );
					pax.util.setPosition( pax.$('pax.util.getPosition.example1.divB'), pos );
				} );
			:]
		(end)

*/
pax.util.setPosition = function( element, pos ) {
	if(typeof( pos.x ) == 'number')element.style.left = pos.x + 'px';
	if(typeof( pos.y ) == 'number')element.style.top = pos.y + 'px';
	if(typeof( pos.width ) == 'number')element.style.width = pos.width + 'px';
	if(typeof( pos.height ) == 'number')element.style.height = pos.height + 'px';
};


/*	Method: pax.util.getWindowDimensions
	Returns a dictionary with width, height of the window.
	
	Parameters:
		none

	Returns:
		A dictionary with width, height of the window.

	Example:
		(start code)
			<div id="pax.util.getWindowDimensions.example1"></div>
			[:.
				var myDiv = pax.$('pax.util.getWindowDimensions.example1');
				var winSize = pax.util.getWindowDimensions();
				myDiv.innerHTML += 'width: ' + winSize.width + ' height: ' + winSize.height + ' scrollLeft: ' + winSize.scrollLeft + ' scrollTop: ' + winSize.scrollTop;
			:]
		(end)
		winSize will be an object that contains { width: int, height: int, scrollLeft: int, scrollTop: int };
*/
pax.util.getWindowDimensions = function( tWindow ) {
	tWindow = ( typeof(tWindow) != 'undefined' )? tWindow: window;
	var myWidth = 0, myHeight = 0;
	if( typeof( window.innerWidth ) == 'number' ) {    // Non IE
		myWidth = window.innerWidth;
		myHeight = window.innerHeight;
		//    It seems that non-IE browsers INCLUDE the scrollbar in the width. We can't calculate that, so estimate it to be 19px
		myWidth -= 19;
	} else if( tWindow.document.documentElement && ( tWindow.document.documentElement.clientWidth || tWindow.document.documentElement.clientHeight ) ) {
		//	IE 6+ in 'standards compliant mode'
		myWidth = tWindow.document.documentElement.clientWidth;
		myHeight = tWindow.document.documentElement.clientHeight;
	} else if( tWindow.document.body && (	tWindow.document.body.clientWidth || tWindow.document.body.clientHeight ) ) {    //IE 4 compatible
		myWidth = tWindow.document.body.clientWidth;
		myHeight = tWindow.document.body.clientHeight;
	}

	var docBody = ( tWindow.document.compatMode && tWindow.document.compatMode != "BackCompat" )?	tWindow.document.documentElement : tWindow.document.body;
	var leftOffset = tWindow.document.all? docBody.scrollLeft : tWindow.pageXOffset;
	var topOffset  = tWindow.document.all? docBody.scrollTop :	tWindow.pageYOffset;
	
	return { width: myWidth, height: myHeight, scrollLeft: leftOffset, scrollTop: topOffset };
};


/*	Method: pax.util.getElementsByClassName
	Return all elements by a given tag name and class name.
	
	Parameters:
		element - The DOM element to search
		elementType -  Type of element to look for, you can use "*" to return all element types
		className - The class name of the elements to return

	Returns:
		An array with the required DOM elements

	Example:
		(start code)
			<div id='pax.getElementsByClassName.example1'></div>
			[:.
				var myElement = pax.util.getElementsByClassName( document, 'div', 'CFunction' );
				pax.$('pax.getElementsByClassName.example1').innerHTML = 'There are ' + myElement.length + ' divs with CFunction as class name.';
			:]
		(end)
		myElement will now be an array with all div elements with a class name of 'CFunction' from the document
*/
pax.util.getElementsByClassName = function( element, elementType, className ) {
	var allElements = (elementType == "*" && element.all)? element.all : element.getElementsByTagName(elementType);
	var classElements = new Array();
	className = className.replace(/\-/g, "\\-");
	var findClass = new RegExp("(^|\\s)" + className + "(\\s|$)");
	for( var i=0; i<allElements.length; i++) {
		var myElement = allElements[i];
		if( findClass.test( myElement.className ) )classElements[classElements.length] = myElement;
	}
	return classElements;
};


/*	Method: pax.util.addClassName
	Adds a class name to an element
	
	Parameters:
		element - The DOM element to add a class name to
		className - The class name you want to add

	Example:
		(start code)
			<div id="pax.util.addClassName.example1"></div>
			[:.
				var newSpan = document.createElement( 'SPAN' );
				newSpan.innerHTML = 'Span';
				newSpan.id = 'pax.util.addClassName.example1.span';
				newSpan.style.position = 'absolute';
				newSpan.style.left = '100px';
				newSpan.style.top = '200px';
				document.body.appendChild( newSpan );
				
				var myNewSpan = pax.$('pax.util.addClassName.example1.span');
				pax.util.addClassName( myNewSpan, 'classOne' );
				pax.util.addClassName( myNewSpan, 'classTwo' );
				pax.$('pax.util.addClassName.example1').innerHTML += 'Class names: [' + myNewSpan.className + ']';
				
				document.body.removeChild( newSpan );
			:]
		(end)
		This will add the class names 'classOne' and 'classTwo' to the newSpan element
*/
pax.util.addClassName = function( element, className ) {
	pax.util.removeClassName( element, className );
	element.className += ( ( element.className.length > 0 )? ' ': '' ) + className;
};


/*	Method: pax.util.hasClassName
	Checks for a class name in an element
	
	Parameters:
		element - The DOM element to check
		className - The class name you want to check for

	Example:
		(start code)
			<div id="pax.util.hasClassName.example1" class="classOne classTwo classThree"></div>
			[:.
				pax.$('pax.util.hasClassName.example1').innerHTML = 'hasClassName (classOne): [' + pax.util.hasClassName( pax.$('pax.util.hasClassName.example1'), 'classOne' ) + ']';
				pax.$('pax.util.hasClassName.example1').innerHTML += ' hasClassName (classFour): [' + pax.util.hasClassName( pax.$('pax.util.hasClassName.example1'), 'classFour' ) + ']';
			:]
		(end)
		This will add the class name 'classOne' to the newSpan element, then remove it.
*/
pax.util.hasClassName = function( element, className ) {
	return (!element || !element.className)? false: (new RegExp("\\b"+className+"\\b")).test(element.className);
};



/*	Method: pax.util.removeClassName
	Removes a class name from an element
	
	Parameters:
		element - The DOM element to remove a class name from
		className - The class name you want to remove

	Example:
		(start code)
			<div id="pax.util.removeClassName.example1"></div>
			[:.
				var newSpan = document.createElement( 'SPAN' );
				newSpan.innerHTML = 'Span';
				newSpan.id = 'pax.util.removeClassName.example1.span';
				newSpan.style.position = 'absolute';
				newSpan.style.left = '100px';
				newSpan.style.top = '200px';
				document.body.appendChild( newSpan );
				
				var myNewSpan = pax.$('pax.util.removeClassName.example1.span');
				pax.util.addClassName( myNewSpan, 'classOne' );
				pax.$('pax.util.removeClassName.example1').innerHTML += 'Before removeClassName: [' + myNewSpan.className + '], ';
				pax.util.removeClassName( myNewSpan, 'classOne' );
				pax.$('pax.util.removeClassName.example1').innerHTML += 'After removeClassName: [' + myNewSpan.className + ']';
				
				document.body.removeChild( newSpan );
			:]
		(end)
		This will add the class name 'classOne' to the newSpan element, then remove it.
*/
pax.util.removeClassName = function( element, className ) {
	if( element ) {
		//	TODO: Fix this - doesn't work when there is no whitespace after the class name???
		
		var myClass = new RegExp( ( className + "\s?" ), "i" );
		element.className = element.className.replace(new RegExp("^" + className + "\\b\\s*|\\s*\\b" + className + "\\b",'g'),'');
		//	element.className = element.className.replace(new RegExp("^" + myClass + "\\b\\s*|\\s*\\b" + myClass + "\\b",'g'),'');
		//	element.className = element.className.split( className ).join('');
	}
};

/*	Method: pax.util.swapClassName
	Removes one class name, and adds another, to an element
	
	Parameters:
		element - The DOM element to swap a class names on
		className1 - The class name you want to remove, this can be a list of class names
		className2 - The class name you want to add, this can be a list of class names

	Example:
		(start code)
			<div id="pax.util.swapClassName.example1"></div>
			[:.
				var myDiv = pax.$('pax.util.swapClassName.example1');
				pax.util.addClassName( myDiv, 'classOne' );
				myDiv.innerHTML += 'Before swapClassName: [' + myDiv.className + '], ';
				pax.util.swapClassName( myDiv, 'classOne', 'classTwo' );
				myDiv.innerHTML += 'After swapClassName: [' + myDiv.className + ']';
			:]
		(end)
		This will add the class name 'classOne' to the newSpan element, then swap it with 'classTwo'.

	Example:
		(start code)
			<div id="pax.util.swapClassName.example2"></div>
			[:.
				var myDiv = pax.$('pax.util.swapClassName.example2');
				pax.util.addClassName( myDiv, 'classOne' );
				pax.util.addClassName( myDiv, 'classTwo' );
				myDiv.innerHTML += 'Before swapClassName: [' + myDiv.className + '], ';
				pax.util.swapClassName( myDiv, ['classOne', 'classTwo'], ['classThree', 'classFour'] );
				myDiv.innerHTML += 'After swapClassName: [' + myDiv.className + ']';
			:]
		(end)
		This will add the class names 'classOne' and 'classTwo' to the element, then swap it with 'classThree' and 'classFour'.
*/
pax.util.swapClassName = function( element, className1, className2 ) {
	if( typeof( className1 ) != 'string' ) {
		//	Assume a list, and remove all
		for( var i = 0; i < className1.length; i++ )pax.util.removeClassName( element, className1[i] );
	} else pax.util.removeClassName( element, className1 );
	if( typeof( className2 ) != 'string' ) {
		//	Assume a list, and add all
		for( var i = 0; i < className2.length; i++ )pax.util.addClassName( element, className2[i] );
	} else pax.util.addClassName( element, className2 );
};


/*	Method: pax.util.toggleClassName
	Toggles one or more class names on an element, uses className1 to determine which classes we're adding or removing
	
	Parameters:
		element - The DOM element to toggle the class name(s) on
		className1 - The first class; this can be a list of class names
		className2 - The second class; this can be a list of class names

	Example:
		(start code)
			<div id="pax.util.toggleClassName.example1"></div>
			[:.
				var myDiv = pax.$('pax.util.toggleClassName.example1');
				pax.util.addClassName( myDiv, 'classOne' );
				myDiv.innerHTML += 'Before first toggleClassName: [' + myDiv.className + '], ';
				pax.util.toggleClassName( myDiv, 'classOne', 'classTwo' );
				myDiv.innerHTML += 'After first toggleClassName: [' + myDiv.className + ']';
				pax.util.toggleClassName( myDiv, 'classOne', 'classTwo' );
				myDiv.innerHTML += 'After second toggleClassName: [' + myDiv.className + ']';
			:]
		(end)
		This will add the class name 'classOne' to the newSpan element, then swap it with 'classTwo', and then back again.
*/
pax.util.toggleClassName = function( element, className1, className2 ) {
	var hasClassName1 = false;
	if( typeof( className1 ) != 'string' ) {
		//	Assume a list
		for( var i = 0; i < className1.length; i++ )if( pax.util.hasClassName( element, className1[i] ) )hasClassName1 = true;
	} else if( pax.util.hasClassName( element, className1 ) )hasClassName1 = true;
	
	if( hasClassName1 )pax.util.swapClassName( element, className1, className2 );
	else pax.util.swapClassName( element, className2, className1 );
	
	return hasClassName1;
};


/*	Method: pax.util.getStyle
	Returns a given property from an element. A property is computed if it is not explicitly set, and may differ from browser to browser.
	
	WIP: Make this more consistent for every browser.
	
		- Really, you don't say - next time add specific instances!
	
	Parameters:
		element - The DOM element to get the style from
		property - The style property you want to get

	Example:
		(start code)
			<div id="pax.util.getStyle.example1"></div>
			[:.
				var fontSize = pax.util.getStyle( pax.$('pax.util.getStyle.example1'), 'font-size' );
				pax.$('pax.util.getStyle.example1').innerHTML += 'Font size: ' + fontSize;
				var myColour = pax.util.getStyle( pax.$('pax.util.getStyle.example1'), 'color' );
				pax.$('pax.util.getStyle.example1').innerHTML += ' Colour: ' + myColour;
			:]
		(end)
		This will display the font size, and color CSS properties of the given element
*/
pax.util.getStyle = function( element, property ) {
	var myStyle = "";
	if( typeof( element ) == 'undefined' || ! element )return null;
	if( document.defaultView && document.defaultView.getComputedStyle ) {
		if( property )myStyle = document.defaultView.getComputedStyle(element, "").getPropertyValue(property);
		else {
			myStyle = {};
			objStyle = document.defaultView.getComputedStyle(element, "");
			for( var i in objStyle ) {
				if( pax.util.getType( objStyle[i] ) != 'function' && i != 'length' ) {
					myStyle[i] = objStyle.getPropertyValue(i);
				}
			}
		}
	} else if( element.currentStyle ) {
		if( property ) {
			property = property.replace(/\-(\w)/g, function (strMatch, p1) { return p1.toUpperCase(); } );
			myStyle = element.currentStyle[property];
		} else {
			myStyle = element.currentStyle;
		}
	}
	return myStyle;
};



// WIP: Make this work correctly in IE, and move to pax.css...
pax.util.setStyle = function( element, properties ) {

	if( typeof( element ) == 'undefined' || ! element )return null;
	//if( document.defaultView && document.defaultView.getComputedStyle ) {
		//var compstyle = document.defaultView.getComputedStyle(element, "");
		for( var i in properties ) {
			var property = i.toLowerCase();
			if( property != 'csstext' && property != 'parentrule' ) {
				//	compstyle.setProperty( i, properties[i], '' );
				
				if( property == 'opacity' ) {
					pax.css.opacity( element, properties[i] );
				} else if( property == 'float' ) {
					element.style['styleFloat'] = properties[i];
					if( element.style.setAttribute )element.style.setAttribute('styleFloat', properties[i]);
				} else {
					element.style[i] = properties[i];
					if( element.style.setAttribute )element.style.setAttribute(i, properties[i]);
				}
			}
		}
		
		
	//} else if( element.currentStyle ) {
		//	TODO: IE 
	//}
	
};
